package org.smartboot.sosa.core.json;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.smartboot.sosa.core.json.ToJsonObject.DateFormat;
import org.smartboot.sosa.core.util.DateUtils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

/**
 * JSON工具类
 * 
 * @author Seer
 * @version JsonUtil.java, v 0.1 2015年11月5日 下午3:22:13 Seer Exp.
 */
public class JsonUtil {
	private static final Logger LOGGER = LogManager.getLogger(JsonUtil.class);

	/**
	 * 将List转化成json对象
	 * 
	 * @param key
	 * @param objArray
	 * @return
	 */
	public static <T> JSONObject getJsonObject(String key, List<T> objArray) {
		return getJsonObject(key, objArray.toArray());
	}

	/**
	 * 将List转化成JSONArray对象
	 * 
	 * @param objArray
	 * @return
	 */
	public static <T> JSONArray getJsonArray(List<T> objArray) {
		JSONArray jsonArray = new JSONArray();
		if (CollectionUtils.isEmpty(objArray)) {
			LOGGER.warn(" value is " + objArray);
			return jsonArray;
		}
		for (T t : objArray) {
			jsonArray.add(JsonUtil.getJsonObject(t));
		}
		return jsonArray;
	}

	/**
	 * 将数组转化成JSONArray对象
	 * 
	 * @param objArray
	 * @return
	 */
	public static <T> JSONArray getJsonArray(T[] objArray) {
		JSONArray jsonArray = new JSONArray();
		if (objArray == null) {
			LOGGER.warn(" value is " + objArray);
			return jsonArray;
		}
		for (T t : objArray) {
			jsonArray.add(JsonUtil.getJsonObject(t));
		}
		return jsonArray;
	}

	/**
	 * 将Map转化成JSONObject对象
	 *
	 * @param map
	 * @return
	 */
	public static <T> JSONObject getJsonMap(Map<String, T> map) {
		JSONObject jsonObject = new JSONObject();
		if (map == null) {
			LOGGER.warn(" value is " + map);
			return jsonObject;
		}
		for (Entry<String, T> entry : map.entrySet()) {
			JSONObject j = JsonUtil.getJsonObject(entry.getValue());
			jsonObject.put(entry.getKey(), j == null ? entry.getValue() : j);
		}
		return jsonObject;
	}

	/**
	 * 将数组转化成json对象
	 *
	 * @param key
	 * @param objArray
	 * @return
	 */
	public static <T> JSONObject getJsonObject(String key, T[] objArray) {
		JSONObject jsonObj = new JSONObject();
		if (key == null || objArray == null) {
			LOGGER.warn("invalid data convert to json, key is " + key + " , and value is " + objArray);
			return jsonObj;
		}
		JSONArray jsonArray = new JSONArray();
		for (T t : objArray) {
			jsonArray.add(JsonUtil.getJsonObject(t));
		}
		jsonObj.put(key, jsonArray);
		return jsonObj;
	}

	/**
	 * 将object对象转换成json对象
	 *
	 * <pre>
	 * 如果obj为某个类的子类，请确保子类与父类中不要存在同名的成员变量
	 * 
	 * </pre>
	 * 
	 * @param obj
	 * @return
	 */
	public static JSONObject getJsonObject(Object obj) {
		if (obj == null) {
			return null;
		}
		if (obj instanceof JSONObject) {
			return (JSONObject) obj;
		}
		if (obj instanceof ToJsonObject) {
			return ((ToJsonObject) obj).toJsonObject();
		}

		JSONObject json = new JSONObject();
		Class<?> curClass = obj.getClass();
		// 基本数据类型以及jdk提供的类不进行json转换

		if (curClass.isPrimitive() || curClass.getName().startsWith("java.lang")) {
			return null;
		}
		do {
			Field[] fields = curClass.getDeclaredFields();
			for (Field f : fields) {
				JSONAnnotation jsonAnnotation = f.getAnnotation(JSONAnnotation.class);
				// 过滤被final、static、JSONAnnotation修饰的成员变量
				if ((f.getModifiers() & Modifier.FINAL) > 0 || (f.getModifiers() & Modifier.STATIC) > 0
					|| (jsonAnnotation != null && jsonAnnotation.ignore())) {
					continue;
				}

				f.setAccessible(true);// 取消Field的访问检查

				String type = f.getType().getName();

				try {
					Object fileVal = f.get(obj);
					if (fileVal == null) {
						continue;
					}
					String keyName = f.getName();
					if (jsonAnnotation != null && StringUtils.isNotBlank(jsonAnnotation.alias())) {
						keyName = jsonAnnotation.alias();
					}
					// 类型转成String
					if (jsonAnnotation != null && jsonAnnotation.tostring()) {
						fileVal = fileVal.toString();
					}
					// 根据value值获取真实类型
					type = fileVal.getClass().getName();

					// 基本数据类型、java.lang包、枚举
					if (f.getType().isPrimitive() || type.startsWith("java.lang")) {
						json.put(keyName, fileVal);
					} else if (Date.class.isInstance(fileVal)) {
						// 是否显示格式化日期对象
						DateFormat dateFormat = jsonAnnotation != null?jsonAnnotation.dateFormat():null;
						if (dateFormat == DateFormat.LONG) {
							json.put(keyName, ((Date) fileVal).getTime());
						} else {
							String dateStr = DateUtils.getDate((Date) fileVal, DateUtils.DEFAULT_FORMAT);
							json.put(keyName, dateStr);
						}
					}
					// 数组循环填充

					else if (f.getType().isArray()) {
						Object[] objArray = (Object[]) fileVal;
						if (objArray == null || objArray.length == 0) {
							continue;
						}
						JSONArray arry = new JSONArray();
						for (Object o : objArray) {
							arry.add(getJsonObject(o));
						}
						json.put(keyName, arry);
					}
					// 集合循环填充

					else if (Collection.class.isInstance(fileVal)) {
						Collection<?> c = (Collection<?>) fileVal;
						if (CollectionUtils.isEmpty(c)) {
							continue;
						}
						JSONArray arry = new JSONArray();
						for (Object o : c) {
							arry.add(getJsonObject(o));
						}
						json.put(keyName, arry);
					} else if (JSONObject.class.isInstance(fileVal)) {
						json.put(keyName, fileVal);
					}
					// 循环Map

					else if (Map.class.isInstance(fileVal)) {
						Map<?, ?> map = (Map<?, ?>) fileVal;
						if (map == null || map.isEmpty()) {
							continue;
						}
						JSONArray array = new JSONArray();
						for (Object key : map.keySet()) {
							JSONObject jo = new JSONObject();
							jo.put(key.toString(), getJsonObject(map.get(key)));
							array.add(jo);
						}
						json.put(keyName, array);
					}
					// 其他类递归填充

					else {
						json.put(keyName, getJsonObject(fileVal));
					}
				} catch (Exception e) {
					LOGGER.warn("", e);
				}
			}
		} while ((curClass = curClass.getSuperclass()) != Object.class);
		return json;
	}

	/**
	 * JSON对象反向生成对象
	 * 
	 * @param json
	 * @param t
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static <T> T parseObject(JSONObject json, Class<T> inputClass) {
		Class<?> curClass = inputClass;
		// 基本数据类型以及jdk提供的类不进行json转换

		if (curClass.isPrimitive() || curClass.getName().startsWith("java.lang")) {
			return null;
		}
		Object obj = null;
		try {
			obj = curClass.newInstance();
		} catch (Exception e) {

			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug(e);
			}
		}
		// 无法实例化则直接返回
		if (obj == null) {
			return null;
		}
		do {

			Field[] fields = curClass.getDeclaredFields();
			for (Field f : fields) {
				// 过滤被final、static、JSONAnnotation修饰的成员变量
				if ((f.getModifiers() & Modifier.FINAL) > 0 || (f.getModifiers() & Modifier.STATIC) > 0) {
					continue;
				}

				f.setAccessible(true);// 取消Field的访问检查
				Class<?> filedType = f.getType();
				String fieldName = f.getName();
				try {
					if (String.class == filedType) {
						f.set(obj, json.getString(fieldName));
					} else if (int.class == filedType) {
						f.setInt(obj, json.getIntValue(fieldName));
					} else if (Date.class == filedType) {
						f.set(obj, json.getDate(fieldName));
					} else if (filedType.isArray()) {
						JSONArray jsonArray = json.getJSONArray(fieldName);
						if (jsonArray == null || jsonArray.isEmpty()) {
							continue;
						}
						int size = jsonArray.size();
						Object array = Array.newInstance(filedType.getComponentType(), size);
						for (int i = 0; i < size; i++) {
							Array.set(array, i, parseObject(jsonArray.getJSONObject(i), filedType.getComponentType()));
						}
						f.set(obj, array);
					} else if (filedType.isAssignableFrom(List.class)) {
						Type genericType = f.getGenericType();
						if (genericType == null) {
							continue;
						}
						Class genericClazz = null;
						// 如果是泛型参数的类型
						if (genericType instanceof ParameterizedType) {
							ParameterizedType pt = (ParameterizedType) genericType;
							genericClazz = (Class) pt.getActualTypeArguments()[0]; // 得到泛型里的class类型对象。
						}
						if (genericClazz == null) {
							continue;
						}
						JSONArray jsonArray = json.getJSONArray(fieldName);
						if (jsonArray == null || jsonArray.isEmpty()) {
							continue;
						}
						int size = jsonArray.size();
						List list = new ArrayList(size);
						for (int i = 0; i < size; i++) {
							list.add(parseObject(jsonArray.getJSONObject(i), genericClazz));
						}
						f.set(obj, list);
					} else {
						f.set(obj, parseObject(json.getJSONObject(fieldName), filedType));
					}
				} catch (Exception e) {
					if (LOGGER.isDebugEnabled()) {
						LOGGER.debug(e);
					}
				}
			}
		} while ((curClass = curClass.getSuperclass()) != Object.class);
		return (T) obj;
	}
}